#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include "hlog.h"

#define NR_THR		2
#define NR_PER_THR	2000L
#define BUF_LEN		(1024*32)

static char *g_prio_str[] = {
	"NULL",
	"info",
	"notice",
	"warn",
	"error",
};

int g_prio = HLOG_PRIO_INFO;

struct thr_t {
	uint64_t total;
	uint64_t nr;
	uint64_t e;
	char *buf;
	uint64_t rsv[4];
};

struct thr_t g_thr[NR_THR];

static inline uint64_t zs_rdtsc(void){
    unsigned int lo,hi;
    __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
    return ((uint64_t)hi << 32) | lo;
}


void *app_thr_func(void *arg)
{
	int i;
	uint64_t t0, t1;
	struct thr_t *thr = (struct thr_t *)arg;
	size_t len;

	len = 0;
	for (i=0; i<NR_PER_THR; i++) {
		usleep(1000);
		if (len >= BUF_LEN)
			len = 0;
		t0 = zs_rdtsc();
		HLOG_LOG(g_prio, "app test, i=%d", i);
		//len += snprintf(thr->buf+len, BUF_LEN-len, "app test, i=%d\n", i);
		//memcpy(thr->buf+len, "hellohellohello", 15);
		len = +15;
		t1 = zs_rdtsc();
		thr->total += (t1 - t0);
		thr->nr++;
	}
	thr->e = 1;
	return NULL;
}

int main(int argc, char *argv[])
{
	pthread_t app[NR_THR];
	time_t t0, t1, td;
	uint64_t n;
	int i;

	if (argc>1) {
		for (i=1; i<HLOG_PRIO_NUM; i++) {
			if (strcmp(g_prio_str[i], argv[1])==0) {
				g_prio = i;
			}
		}
	}
	printf("g_prio=%d, %s\n", g_prio, g_prio_str[g_prio]);

	printf("pid = %d\n", getpid());

	hlog_init("hlog.log", "hlog.mmap", HLOG_PRIO_WARN,
			HLOG_PRIO_NOTICE, HLOG_PRIO_INFO);
	HLOG_INFO("hello");

	printf("NR_THR = %d\n", NR_THR);
	time(&t0);
	for (i = 0; i < NR_THR; i++) {
		g_thr[i].buf = calloc(1, BUF_LEN);
		assert(g_thr[i].buf);
		pthread_create(&app[i], NULL, app_thr_func, &g_thr[i]);
	}

	while(1) {
		uint64_t nr, total;
		double avg;

		sleep(1);
		hlog_dump();
		nr = 0;
		total = 0;
		for (i = 0; i < NR_THR; i++) {
			nr += g_thr[i].nr;
			total += g_thr[i].total;
			printf(" i=%d, total=%lu, nr=%lu\n",
				i, g_thr[i].total, g_thr[i].nr);
			g_thr[i].nr = 0;
			g_thr[i].total = 0;
		}
		avg = (nr==0 ? 0 : (1.0 * total / nr));
		printf("total=%lu, nr=%ld, avg=%5.0fcycles\n", total, nr, avg);
		n = 0;
		for (i = 0; i < NR_THR; i++) {
			n += g_thr[i].e;
		}
		if (n >= NR_THR)
			break;
	}

	for (i = 0; i < NR_THR; i++)
		pthread_join(app[i], NULL);

	time(&t1);
	td = t1 - t0;
	printf("td=%ld\n", td);
	if (td > 0)
		printf("%ld logs/sec\n", (NR_THR * NR_PER_THR) / td);

	hlog_exit();
	return 0;
}


